<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<script>
  //正常帧任务完成后没超过16 ms,说明时间有富余，此时就会执行 requestIdleCallback 里注册的任务

  function sleep(delay){
    console.log('sleep~~~~~');
    for (let t = Date.now(); Date.now() - t <= delay;) {}
  }

  console.time('haveruntime')

  // fiber是把整个任务分成很多个小任务 每次执行一个任务
  // 执行完成后会看看有没有剩余时间 如果有继续下一个任务 如果没有 放弃执行 交给浏览器进行调度 等待下次执行
  // componentWillMount、WillUpdate、WillReceiveProps 在这种设计下 可能会多次调用 故被废弃了

  const works = [
    () => {
      console.log('第1个任务开始');
      sleep(20); // 超过一帧的执行时间了
      console.log('第1个任务结束');
    },() => {
      console.log('第2个任务开始');
      sleep(20);
      console.log('第2个任务结束');
    },() => {
      console.log('第3个任务开始');
      sleep(20);
      console.log('第3个任务结束');
      console.timeEnd('haveruntime')
    }
  ];

  //react使用的MessageChannel+requestAnimationFrame 模拟的, 因为 requestIdleCallback 目前只有chrome支持
  window.requestIdleCallback(workLoop, {timeout: 1000 /** ←最迟执行期限*/});

  function workLoop(idleDeadline){
    console.log('===新的一帧===');
    console.log('didTimeout:',idleDeadline.didTimeout);
    console.log('本帧的剩余时间为:',idleDeadline.timeRemaining()); // 会发现这个剩余时间有时可能会超过16ms(或则你的屏幕刷新速率) emmm... 比如谷歌是40+ms
    // 如果系统一直处于繁忙(一帧中没有空闲时间了) 这个函数回调(workLoop)会一直得不到执行

    /**
      deadline是一个对象 有两个属性

      + timeRemaining 可以返回此帧还剩下多少时间供用户使用, 如果idle period已经结束，则它的值是0

      + didTimeout: boolean(根据 timeout 计算是否超时)
        >https://developer.mozilla.org/en-US/docs/Web/API/IdleDeadline/didTimeout
        >
        >A Boolean which is true if the callback is running due to the callback's timeout period elapsing or false if the callback is running because the user agent is idle and is offering time to the callback.
        >
        >The read-only didTimeout property on the IdleDeadline interface is a Boolean value which indicates whether or not the idle callback is being invoked because the timeout interval specified when Window.requestIdleCallback() was called has expired.
        >
        >If didTimeout is true, the IdleDeadline object's timeRemaining() method will return approximately 0.
    */

    // performUnitOfWork();
    // ↕一帧的空余时间 如果时间允许(deadline.timeRemaining还有剩,即大于0) 应该可以执行多个任务 故这里用while
    while ((idleDeadline.timeRemaining() > 0 || idleDeadline.didTimeout/*如果已经超时了,就要抓紧立即一口气执行完,不要再分片了*/) && works.length > 0) {
      performUnitOfWork();
      console.log('本帧的剩余时间为:',idleDeadline.timeRemaining());
    }

    if (works.length > 0) {
      window.requestIdleCallback(workLoop, {timeout: 1000});
    }
  }

  function performUnitOfWork() {
    // shift取出数组中的第1个元素
    works.shift()();
  }
</script>
</body>
</html>
